WorkManager基本使用及源码分析(六) - SystemForegroundService
目 录
目录
源码篇 上一篇中我们了解了WorkManager使用的的主要组件,猜测了各个组件的作用,并简单介绍了WorkManager是如何初始化的。本篇将延续前文,介绍WorkManager中Service组件之一的SystemForegroundService。
SystemForegroundService
在看过前面SystemAlarmService & SystenJobService
后,我本以为SystemForegroundService
也如前者一般是处理任务执行的,但简单阅读代码后发现并非如此,尽管结构上与前者类似,但其主要作用是给运行任务的服务提权,保证其在前台执行 。
SystemAlarmService & SystenJobService
相似,SystemForegroundService
也是LifecycleService
的子类,主要方法有:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 @Override public void onCreate () { super .onCreate(); sForegroundService = this ; initializeDispatcher(); } @Override public int onStartCommand (@Nullable Intent intent, int flags, int startId) { super .onStartCommand(intent, flags, startId); if (mIsShutdown) { mDispatcher.onDestroy(); initializeDispatcher(); mIsShutdown = false ; } if (intent != null ) { mDispatcher.onStartCommand(intent); } return Service.START_REDELIVER_INTENT; } @MainThread private void initializeDispatcher () { mHandler = new Handler(Looper.getMainLooper()); mNotificationManager = (NotificationManager) getApplicationContext().getSystemService(Context.NOTIFICATION_SERVICE); mDispatcher = new SystemForegroundDispatcher(getApplicationContext()); mDispatcher.setCallback(this ); }
初始化时创建新的SystemForegroundDispatcher绑定并设置新的生命周期,当收到指令被启动时,调用SystemForegroundDispatcher.onStartCommand()
:
1 2 3 4 5 6 7 8 9 10 11 12 13 void onStartCommand (@NonNull Intent intent) { String action = intent.getAction(); if (ACTION_START_FOREGROUND.equals(action)) { handleStartForeground(intent); handleNotify(intent); } else if (ACTION_NOTIFY.equals(action)) { handleNotify(intent); } else if (ACTION_CANCEL_WORK.equals(action)) { handleCancelWork(intent); } }
当intent (此处intent可视作前面提到的SystemXXXService的意图 ) 状态处于启动、更新状态时会调用handleNotify(intent)
,取消时会调用handleCancelWork(intent)
, 状态为取消时,则最终会调用mWorkManagerImpl.cancelWorkById(UUID.fromString(workSpecId))
取消任务执行。
我们再来看看handleNotify干了哪些事情吧:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 @MainThread private void handleNotify (@NonNull Intent intent) { int notificationId = intent.getIntExtra(KEY_NOTIFICATION_ID, 0 ); int notificationType = intent.getIntExtra(KEY_FOREGROUND_SERVICE_TYPE, 0 ); String workSpecId = intent.getStringExtra(KEY_WORKSPEC_ID); Notification notification = intent.getParcelableExtra(KEY_NOTIFICATION); if (notification != null && mCallback != null ) { ForegroundInfo info = new ForegroundInfo( notificationId, notification, notificationType); mForegroundInfoById.put(workSpecId, info); if (TextUtils.isEmpty(mCurrentForegroundWorkSpecId)) { mCurrentForegroundWorkSpecId = workSpecId; mCallback.startForeground(notificationId, notificationType, notification); } else { mCallback.notify(notificationId, notification); if (notificationType != FOREGROUND_SERVICE_TYPE_NONE && Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { int foregroundServiceType = FOREGROUND_SERVICE_TYPE_NONE; for (Map.Entry<String, ForegroundInfo> entry : mForegroundInfoById.entrySet()) { ForegroundInfo foregroundInfo = entry.getValue(); foregroundServiceType |= foregroundInfo.getForegroundServiceType(); } ForegroundInfo currentInfo = mForegroundInfoById.get(mCurrentForegroundWorkSpecId); if (currentInfo != null ) { mCallback.startForeground( currentInfo.getNotificationId(), foregroundServiceType, currentInfo.getNotification() ); } } } } }
若当前服务intent是首个,那么就启动SystemForegroundService.startForeground()
做周期性递归,而SystemForegroundService.startForeground()
实际上是一个空方法,类似于使用了Looper
保证SystemForegroundService
一直运行:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 // SystemForegroundService#startForeground @Override public void startForeground( final int notificationId, final int notificationType, @NonNull final Notification notification) { mHandler.post(new Runnable() { @Override public void run() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { startForeground(notificationId, notification, notificationType); } else { startForeground(notificationId, notification); } } }); }
若当前服务intent不是首个,则更新一则通知,并合并前台服务类型,mCallback.notify(notificationId, notification)
:
1 2 3 4 5 6 7 8 9 10 @Override public void notify (final int notificationId, @NonNull final Notification notification) { mHandler.post(new Runnable() { @Override public void run () { mNotificationManager.notify(notificationId, notification); } }); }
总结 SystemForegroundService
会在任务启动时启动,且会创建一个类似于Looper
的结构保持服务前台持续运行,后续有任务触发时,会发送notification以保证其执行任务的服务可被视作前台服务保持运行。